#!/usr/bin/python
#AUTHOR: ALBERT RONDAN 
#this file takes the desired courses, desired number of courses, and constraints and converts said data into a ASP program. this program is executed within this file and the output is sent back to the webpage

import re, string
import cgi
import cgitb

#Here is the new createInput( inpt ) function
#a Dictionary is created and populated with the selected input database. The function then goes through the selected inpt that is passed in as a parameter and uses the dictionary to find the related classes and add them to the logic program.
#it would be great if I found a way to cache the dictionary once its created. but essentiall you only create/use the dictionary that the user selects (if they select a college)
#this also handles generic event input
def createInput( inpt ) : 
	#make sure the list isn't empty...
	if len(inpt)==0:
		#print "NO INPUT WAS GIVEN" 
		return ""
	#also, there will be the option to select which database we are extracting from. so our database ends up just being text files that are selected.
	mapping = {}
	
	r = open('clingoinput','r')
	line=r.readline()

	while line != "" :
		line=line.rstrip()
		coursename = line[line.find("(")+1:line.find(",")]
		if coursename in mapping :
			curlist = mapping[coursename]
			curlist.append(line)
			mapping[coursename] = curlist
		else :
			tmplist = []
			tmplist.append(line)
			mapping[coursename] = tmplist	

		line=r.readline()

	
	
	print "Generating Inputs..."
	logicInput = ""
	inpt.sort()
	for event in inpt :
		pattern = re.compile('[^A-Za-z0-9]+')		
		compare = pattern.sub('',event)
		compare = compare.lower()
		#Now event is ready to be used.
		#check to see if it is in the course schedule selected.
				
		if compare in mapping :		
			for instance in mapping[compare] :
				logicInput+=instance + "\n"
		else : 
			logicInput+=event + "\n"
		

	r.close()

	#x = open('inputs.txt','w')	
	#x.write(str(logicInput))	
	#x.close()

	print "Done"
	return logicInput

def createNTFT(lst) : 
	logicProgram =""
	#lst is the list with all necessary criteria. Similarly inpt is a list with all the input NTFT will be using
	req = re.split(",",lst[0])
	n = req[0]
	# n is bound for choice rule. The total number of events to factor into schedule.
	xtruth=False
	#we can now create the core part of the ntft
	print "Creating Program \'ntftprogram\'..."

	#insert converted criteria here OR BEFORE HAND depending on whether or not the criteria has to do with class times or not ( it would save a lot of grounding 		time if the criteria is in its most efficient place. also, order criteria in general so that more specific/demanding tasks are done last (or first? i cant 		decide)
	print "\tWriting Criteria..."	

	#loop through criteria list and add restraints to ntft program
	for strng in lst :
		crit = re.split(" ",strng)
		if crit[0] == "B" :
			class1=crit[1]
			class2=crit[2]
			logicProgram+="\n\n:- pos("+class1+",O), pos("+class2+",O1), event("+class1+",O,D,S,F), event("+class2+",O1,D,S1,F1), S1<S."
		elif crit[0] == "BTB":
			logicProgram+="\n\n:- pos(E,O), pos(E1,O1), event(E,O,D,S,F), event(E1,O1,D,S1,F1), E!=E1, S!=F1, F!=S1."
		elif crit[0] == "LOCK" :
			UID = crit[1]
			logicProgram+="\n\n:- not pos(E,"+UID+"), event(E,"+UID+",_,_,_)."
		elif crit[0] == "N":
			day = crit[2]
			time = crit[1]
			logicProgram+="\n\n:- pos(E,O), pos(E1,O1), event(E,O,"+day+",S,F), event(E1,O1,"+day+",S1,F1), F1-S > "+time+"."
		elif crit[0] == "RT" : 
			start=crit[1]
			finish = crit[2]
			logicProgram+="\n\n:- pos(E,O), event(E,O,D,S,F), S>="+start+", S<"+finish+", F>"+start+", F<="+finish+"."
		elif crit[0] == "RTD" : 
			day = crit[1]
			start=crit[2]
			finish = crit[3]
			logicProgram+="\n\n:- pos(E,O), event(E,O,D,S,F), D=="+day+", S>="+start+", S<"+finish+", F>"+start+", F<="+finish+"."
		elif crit[0] == "XOY" :
			x = crit[1]
			xtruth=True

	logicProgramHeader=""
	logicProgramHeader+="%File ntft \n"
	if(xtruth) :
		logicProgramHeader+=str(x)+" { pos(E,O) : event(E,O,_,_,_) } "+x+". \n\n"
	else :
		logicProgramHeader+=str(n)+" { pos(E,O) : event(E,O,_,_,_) } "+n+". \n\n"	
	logicProgramHeader+=":- pos(E,O), pos(E,O1), O!=O1. \n\n:- pos(E,O), pos(E1,O1), event(E,O,D,S,F), event(E1,O1,D,S1,F1),E!=E1, O!=O1, S<F1, S1<F."	
	
		
	#this is the last bit we need to show the results.
	logicProgram+="\n\neventnew(E,O,D,S,F) :- pos(E,O), event(E,O,D,S,F)."
	logicProgram+="\n\n#hide.\n#show eventnew/5."	
	
	print "Done... Enjoy your solver."
	logicProgram=logicProgramHeader+""+logicProgram
	#x = open('combined.txt','w')	
	#x.write(str(logicProgram))	
	#x.close()

	return logicProgram
def createGeneric(lst) :
	print "Compiling generic inputs..." + str(len(lst))
	if lst[0]=='' :
		return ""
	# format of lst[I] :: [TITLE] [UNIQUEID] [DAY1,DAY2,ETC] [STARTTIMEAM/PM] [FINISHTIMEAM/PM]
	genericInput = "%This section is for generic event input \n\n"
	for strng in lst :
		event = re.split("-",strng)
		
		pattern = re.compile('[^A-Za-z0-9]+')		
		title = pattern.sub('',event[0])
		title = title.lower()

		uid = pattern.sub('',event[1])
		uid = uid.lower()
		starttime= event[3].replace(":","")
		if "pm" in starttime :
			#inclusive:exclusive
			starttime= starttime[0:starttime.find("p")]
			starttime = str(int(starttime)+1200)
		else :
			starttime = starttime[0:starttime.find("a")]

		finishtime= event[4].replace(":","")
		if "pm" in finishtime :
			#inclusive:exclusive
			finishtime= finishtime[0:finishtime.find("p")]
			finishtime = str(int(finishtime)+1200)
		else :
			finishtime = finishtime[0:finishtime.find("a")]

		
		# Make an event for each day
		days = re.split(",",event[2])
		for day in days :
			day = pattern.sub('',day)
			day = day.lower()
			genericInput+="event("+title+","+uid+","+day+","+starttime+","+finishtime+"). \n"		
		
	print "Done"
	print genericInput
	return genericInput

def main() :
	print
	cgitb.enable()
	#print "lets try to retrieve the parameters and print them out </br>"
	f = str(cgi.FieldStorage())
	#We need to store the parameters given into lists
	#print f	
	#print "</br>"
	
	classes = f[f.find("class=")+7:f.find("consts=")-1]
	classList = re.split(",,",classes)
	#print classList
	#print "</br>"

	#constraints = f[f.find("consts=")+7:f.find(")")-1]
	constraints = f[f.find("consts=")+7:f.find("events=")-1]	
	constraintList = re.split(",",constraints)
	#print constraints	

	events = f[f.find("events=")+7:f.find(")")-1]
	eventsList = re.split(",,",events)
	#print events


	#print f


	#this next line is for testing purposes only (adding the variable n and btb)
	#constraintList.insert(0,"5,0")	
	#So here, You need to specify; From the given list of desired classes, I want at least n number of them to be on my schedule
	numClasses = len(classList)
	numGeneric = 0
		#num Generic is the number of seperate generic events the user wants. it's special because up to this point we havent kept track of how many titles there are. thats the nuber we want. so we loop and find it.
	titles = []
	for event in eventsList :
		cmpr = event[0:event.find("-")]
		#print cmpr
		if cmpr not in titles :
			titles.append(cmpr)
	numGeneric=len(titles)

	if eventsList[0]=='':
		numGeneric=0
	if classList[0]=='':
		numClasses=0			
	#print numGeneric
	constraintList.insert(0,str(numClasses+numGeneric)+",0")
	#print constraintList
	#print "</br>"


	#Here, I am testing output back to the page and piping input into clingo
	#clingoprogram = "p(1)."


	import subprocess


	#p = subprocess.Popen('cd /opt/NTFTC \n pwd \n clingo ntftprogram ntftinput 1',shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	#p = subprocess.Popen("echo \""+clingoprogram+"\" | clingo 1",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	#display(p)
	#outputs the stable model of clingo program. this means we don't have to create physical files, we can just pipe the program straight to clingo and have it produce the answer sets.
	

#debug code
	#eventsList = ["walk Dog-333-m,w,f-10:00am-11:00pm"]
	#classList = ["CS 337 ANALYSIS OF PROGRAMS"]
	#constraintList = ["1,0"]
	
#adding generic events here
	LG = createGeneric(eventsList)
	LI = createInput(classList)
	LP = createNTFT(constraintList)
	
	
	logicProgram = LG + "\n" + LI + "\n" + LP
	#print "</br>"
	#print logicProgram
	#Verify the program	
	#r = open("dump.txt","w")
	#r.write(logicProgram)
	#r.write("\n\n")
	#r.write(str(constraintList))

	#r.write("\n\n")
	#r.write(str(classList))

	#r.write("\n\n")
	#r.write(str(eventsList))

	#r.close()	
	#print logicProgram
	
	#for localhost windows
	#r = open("pipe.txt","w")
	#r.write(logicProgram)
	#r.close()
	
	p = subprocess.Popen("echo \""+logicProgram+"\" | /usr/lib/cgi-bin/NTFTRunner/clingo 100 ",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	#p = subprocess.Popen("more pipe.txt | C:\\xampp\\cgi-bin\\NTFTRunner\\clingo 100 ",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	#p = subprocess.Popen("echo ""p(1). p(2). :- p(1)."" | C:\\xampp\\cgi-bin\\NTFTRunner\\clingo 100 ",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

	display(p)
	#for verification with my xls.py program. Comment if necessarry.

def display(command): 
	totalOut=""
	r = open('output.txt','w')
	for line in command.stdout.readlines():
    		#print line,
		r.write(line)
		totalOut+=line+"\n"
	retval = command.wait()
	r.close()
	
	answerList = re.split("Answer:",totalOut)
#I get some errors here on browsers, I think I am just going to use a try catch
	try :
		answerList.remove('')
	except Exception:
		pass
	#answerList.remove('')
	#print answerList
	#print "</br>"
	formatted = "" 
	for answer in answerList:
		splitanswer = answer.split("eventnew")
		formatted+="["
		i = 1
		while i < len(splitanswer) :
			#print event+" "
			event = splitanswer[i]
			if i == len(splitanswer)-1 :
				event = event[0:event.find("SATISFIABLE")]
			formatted+=event
			formatted+=","
			i+=1
		formatted+="]"
	print formatted		
	
mapping = dict()
main()




#lst = ["4,0","B 1 2","RD m","RT 1300 1500","RTD m 1230 1330"]
	#test list
	#test = ["5,0"]	
	#inpt = ["C S 310 COMPUTER ORGANIZATION AND PROG","E E 316 DIGITAL LOGIC DESIGN","E E 316 LABORATORY","HIS 315L THE UNITED STATES SINCE 1865","BIO 311D INTRODUCTORY BIOLOGY II"]
	#createInput(inpt)
	#createNTFT(test)
